﻿using System;
using Lidgren.Network;
using Lidgren.Network.Xna;
using Microsoft.Xna.Framework;

namespace D2D2.SharedInterfaces.Networking
{
    public enum MonsterType
    {
        Common = 1,
        Champion = 2,
        Unique = 3
    }

    public enum MonsterView
    {
        Blue = 1,
        Green = 2
    }

    public class MonsterObject : BaseMessage
    {
        private readonly Random _rand = new Random();
        private float _timeSinceHit;
        private float _targetLive;

        public MonsterObject(NetIncomingMessage message)
            : base(message)
        {
            Alive = true;
        }

        public MonsterObject()
        {
            Alive = true;
        }

        public bool Alive { get; set; }

        public MonsterType MonsterType { get; set; }
        public MonsterView MonsterView { get; set; }
        public int Level { get; set; }
        public Vector2 Location { get; set; }

        public float TotalLive { get; set; }
        public float CurrentLive { get; set; }
        
        public int MinDamage { get; set; }
        public int MaxDamage { get; set; }

        /// <summary>
        /// Сколько жизней регенерируется за 1 сек.
        /// </summary>
        public float LiveRegen { get; set; }

        public float HitTime { get; set; }

        public bool InDecreasingHit { get; private set; }
        public bool HasResponse { get; set; }

        public PlayerObject TargetPlayer { get; set; }

        public void Hit(PlayerObject player, double messageTime)
        {
            if (!InDecreasingHit)
            {
                InDecreasingHit = true;

                _timeSinceHit = 0;

                int damage = player.GetDamage();

                _targetLive = CurrentLive - damage;

                if (_targetLive > 0)
                    TargetPlayer = player;
            }
        }

        public bool IsClient { get; set; }

        public bool CalculateLive(float elapsed)
        {
            if (InDecreasingHit)
            {
                _timeSinceHit += elapsed;
                float remainingTime = HitTime - (_timeSinceHit - elapsed);

                float deltaLive = (CurrentLive - _targetLive)*elapsed/remainingTime;

                float calculatedLive = CurrentLive - deltaLive;

                if (calculatedLive <= _targetLive)
                {
                    CurrentLive = _targetLive;
                    _targetLive = TotalLive;
                    InDecreasingHit = false;
                    _timeSinceHit = 0;
                    HasResponse = true;
                }
                else
                    CurrentLive = MathHelper.Max(_targetLive, calculatedLive);
                    
                if (calculatedLive <= 0)
                {
                    Alive = false;
                    HasResponse = false;
                }

                return true;
            }

            if (CurrentLive < TotalLive)
            {
                CurrentLive = MathHelper.Min(CurrentLive + elapsed*LiveRegen, TotalLive);
                return true;
            }

            return false;
        }

        public int GetDamage()
        {
            return _rand.Next(MinDamage, MaxDamage + 1);
        }

        public override GameMessageType MessageType
        {
            get { return GameMessageType.MonsterState; }
        }

        public override void Encode(NetOutgoingMessage message)
        {
            message.Write(Id);
            message.Write((byte) MonsterType);
            message.Write((byte) MonsterView);
            message.Write(Level);
            message.Write(Location);
            message.Write(TotalLive);
            message.Write(CurrentLive);
            message.Write(MinDamage);
            message.Write(MaxDamage);
            message.Write(LiveRegen);
            message.Write(HitTime);
            message.Write(InDecreasingHit);
            message.Write(Alive);
        }

        public override void Decode(NetIncomingMessage message)
        {
            Id = message.ReadInt64();
            MonsterType = (MonsterType) message.ReadByte();
            MonsterView = (MonsterView) message.ReadByte();
            Level = message.ReadInt32();
            Location = message.ReadVector2();
            TotalLive = message.ReadFloat();
            CurrentLive = message.ReadFloat();
            MinDamage = message.ReadInt32();
            MaxDamage = message.ReadInt32();
            LiveRegen = message.ReadFloat();
            HitTime = message.ReadFloat();
            InDecreasingHit = message.ReadBoolean();
            Alive = message.ReadBoolean();
        }

        public MonsterObject Clone()
        {
            MonsterObject monster = new MonsterObject();
            monster.Id = Id;
            monster.MonsterType = MonsterType;
            monster.MonsterView = MonsterView;
            monster.Level = Level;
            monster.Location = Location;
            monster.TotalLive = TotalLive;
            monster.CurrentLive = CurrentLive;
            monster.MinDamage = MinDamage;
            monster.MaxDamage = MaxDamage;
            monster.LiveRegen = LiveRegen;
            monster.HitTime = HitTime;
            monster.MessageTime = MessageTime;
            monster.InDecreasingHit = InDecreasingHit;
            monster.Alive = Alive;
            monster.LocalTime = LocalTime;

            return monster;
        }

        public int GetWidth()
        {
            switch (MonsterView)
            {
                case MonsterView.Blue:
                    return 80;
                case MonsterView.Green:
                    return 80;

                default:
                    return 0;
            }
        }

        public int GetHeight()
        {
            switch (MonsterView)
            {
                case MonsterView.Blue:
                    return 80;
                case MonsterView.Green:
                    return 80;

                default:
                    return 0;
            }
        }
    }
}
